package com.ts.opengl.simpleDraw

import android.content.Context
import android.graphics.BitmapFactory
import android.opengl.GLES20
import android.opengl.GLES20.GL_LINEAR
import android.opengl.GLES20.GL_NEAREST
import android.opengl.GLES20.GL_SAMPLER_2D
import android.opengl.GLES20.GL_TEXTURE_2D
import android.opengl.GLES20.GL_TEXTURE_MAG_FILTER
import android.opengl.GLES20.GL_TEXTURE_MIN_FILTER
import android.opengl.GLES20.glBindTexture
import android.opengl.GLES20.glGenTextures
import android.opengl.GLES20.glTexParameteri
import android.opengl.GLES20.glUseProgram
import android.opengl.GLES30
import android.opengl.GLES30.GL_INTERLEAVED_ATTRIBS
import android.opengl.GLES30.glTransformFeedbackVaryings
import android.opengl.GLUtils
import android.util.Log
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import java.nio.IntBuffer
data class TextureBean(var id: Int, var width: Int,var height: Int) {
    constructor():this(-1,0,0)
}
class openglUtil {



    companion object{


        fun createFrameBuffer(
            frameBuffer: IntArray, frameBufferTexture: IntArray,
            width: Int, height: Int
        ) {
            Log.e(TAG,"frameBuffer1"+width+"---"+height)
            //产生FBO ID
            GLES20.glGenFramebuffers(frameBuffer.size, frameBuffer, 0)
            //产生纹理ID
            GLES20.glGenTextures(frameBufferTexture.size, frameBufferTexture, 0)
            for (i in frameBufferTexture.indices) {
                //绑定纹理
                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameBufferTexture[i])
                //加载图像数据, 并上传纹理
                //pixels 可能是一个空指针。在这种情况下，会分配纹理内存以适应宽度width和高度的纹理height
                GLES20.glTexImage2D(
                    GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA,
                    GLES20.GL_UNSIGNED_BYTE, null
                )

                GLES20.glTexParameteri(
                    GLES20.GL_TEXTURE_2D,
                    GLES20.GL_TEXTURE_MAG_FILTER,
                    GLES20.GL_LINEAR
                )
                GLES20.glTexParameteri(
                    GLES20.GL_TEXTURE_2D,
                    GLES20.GL_TEXTURE_MIN_FILTER,
                    GLES20.GL_NEAREST
                )
                GLES20.glTexParameteri(
                    GLES20.GL_TEXTURE_2D,
                    GLES20.GL_TEXTURE_WRAP_S,
                    GLES20.GL_CLAMP_TO_EDGE
                )
                GLES20.glTexParameteri(
                    GLES20.GL_TEXTURE_2D,
                    GLES20.GL_TEXTURE_WRAP_T,
                    GLES20.GL_CLAMP_TO_EDGE
                )
                //绑定
                GLES20.glBindFramebuffer(
                    GLES20.GL_FRAMEBUFFER,
                    frameBuffer[i])
                //将texture和level指定的纹理图像附加为当前绑定的帧缓冲区对象的逻辑缓冲区之一
                GLES20.glFramebufferTexture2D(
                    GLES20.GL_FRAMEBUFFER,
                    GLES20.GL_COLOR_ATTACHMENT0,
                    GLES20.GL_TEXTURE_2D,
                    frameBufferTexture[i], 0
                )
                //解绑纹理
                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0)
                //解绑FBO
                GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0)
            }
//            checkGlError("createFrameBuffer")
        }

        var vShaderStr =
            "#version 300 es layout(location = 0) in vec4 vPosition; void main() { gl_Position = vPosition; }";
        var fShaderStr=
            "#version 300 es precision mediump float; out vec4 fragColor; void main()  { fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 ); }"
        private  val TAG = "openglUtil"

        fun createProgramWithFeedBack(context: Context,verId:Int,frgId:Int):Int{

            val fracre=compileShader(GLES30.GL_FRAGMENT_SHADER,readRawTextFile(context,frgId))

            val vercre=compileShader(GLES30.GL_VERTEX_SHADER,readRawTextFile(context,verId))


            val program=GLES30.glCreateProgram();
            GLES30.glAttachShader(program,vercre)
            GLES30.glAttachShader(program,fracre)
            var  varyings= arrayOf("","")
            glTransformFeedbackVaryings(program, varyings, GL_INTERLEAVED_ATTRIBS);
            GLES30.glLinkProgram(program)
//            glUseProgram(program)
            GLES30.glDeleteShader(vercre)
            GLES30.glDeleteShader(fracre)

            return program;
        }


        fun createProgram(context: Context,verId:Int,frgId:Int):Int{

            val fracre=compileShader(GLES30.GL_FRAGMENT_SHADER,readRawTextFile(context,frgId))

            val vercre=compileShader(GLES30.GL_VERTEX_SHADER,readRawTextFile(context,verId))


            val program=GLES30.glCreateProgram();
            GLES30.glAttachShader(program,vercre)
            GLES30.glAttachShader(program,fracre)

            GLES30.glLinkProgram(program)
//            glUseProgram(program)
            GLES30.glDeleteShader(vercre)
            GLES30.glDeleteShader(fracre)

            return program;
        }


        fun createNoUsingProgram(context: Context,verId:Int,frgId:Int):Int{

            val fracre=compileShader(GLES30.GL_FRAGMENT_SHADER,readRawTextFile(context,frgId))

            val vercre=compileShader(GLES30.GL_VERTEX_SHADER,readRawTextFile(context,verId))


            val program=GLES30.glCreateProgram();
            GLES30.glAttachShader(program,vercre)
            GLES30.glAttachShader(program,fracre)

            GLES30.glLinkProgram(program)
//            glUseProgram(program)
            GLES30.glDeleteShader(vercre)
            GLES30.glDeleteShader(fracre)

            return program;
        }

        fun createTexture(context:Context,resId:Int):TextureBean?{
            var mTextureBean=TextureBean()
            val texture=IntArray(1)
            glGenTextures(0,texture,0)
            glBindTexture(GL_TEXTURE_2D,texture[0])


            BitmapFactory.Options().apply {
                inScaled = false
                val bitmap = BitmapFactory.decodeResource(context.resources, resId, this)
                if (bitmap == null) {
                    GLES30.glDeleteTextures(1,texture,0)
                    Log.d(TAG, "loadTexture fail,bitmap is null ")
                    return null
                }
            //纹理环绕
            glTexParameteri(GLES30.GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST)
            glTexParameteri(GLES30.GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR)
            //纹理过滤
            GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,GLES30.GL_TEXTURE_MIN_FILTER,
                GLES30.GL_NEAREST)
            GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,GLES30.GL_TEXTURE_MAG_FILTER,GLES30.GL_LINEAR)


            GLUtils.texImage2D(GLES30.GL_TEXTURE_2D,0,bitmap,0)
                //告诉opengl 渲染采样模式
            GLES30.glGenerateMipmap(GLES30.GL_TEXTURE_2D)
                //回收bitmap
                mTextureBean.id = texture[0]
                mTextureBean.width = bitmap.width
                mTextureBean.height = bitmap.height
                GLES30.glBindTexture(GLES30.GL_TEXTURE_2D,0)

            }

            return mTextureBean;
        }

        fun createByteBuffer(array: ByteArray): ByteBuffer {
            val buffer = ByteBuffer
                // 分配顶点坐标分量个数 * Float占的Byte位数
                .allocateDirect(array.size * 4)
                // 按照本地字节序排序
                .order(ByteOrder.nativeOrder())
                // Byte类型转Float类型

            // 将Dalvik的内存数据复制到Native内存中
            buffer.put(array)
            buffer.position(0)
            return buffer
        }
        fun createIntBuffer(array: IntArray): IntBuffer {
            val buffer = ByteBuffer
                // 分配顶点坐标分量个数 * Float占的Byte位数
                .allocateDirect(array.size * 4)
                // 按照本地字节序排序
                .order(ByteOrder.nativeOrder())
                // Byte类型转Float类型
                .asIntBuffer()

            // 将Dalvik的内存数据复制到Native内存中
            buffer.put(array)
            buffer.position(0)
            return buffer
        }
        fun createFloatBuffer(array: FloatArray): FloatBuffer {
            val buffer = ByteBuffer
                // 分配顶点坐标分量个数 * Float占的Byte位数
                .allocateDirect(array.size * 4)
                // 按照本地字节序排序
                .order(ByteOrder.nativeOrder())
                // Byte类型转Float类型
                .asFloatBuffer()

            // 将Dalvik的内存数据复制到Native内存中
            buffer.put(array)
            buffer.position(0)
            return buffer
        }
        private fun compileShader(type: Int, shaderCode: String): Int {
//            val shaderId=GLES30.glCreateShader(type)
//            GLES30.glShaderSource(shaderId,shaderCode)
//            GLES30.glCompileShader(shaderId)
//                            val compileStatus = IntArray(1)
//                GLES30.glGetShaderiv(shaderId, GLES30.GL_COMPILE_STATUS, compileStatus, 0)
//                if (compileStatus[0] == 0) {
//                    val logInfo = GLES30.glGetShaderInfoLog(shaderId)
//                    System.err.println(logInfo)
//                    Log.e(TAG,logInfo);
//                    //创建失败
//                    GLES30.glDeleteShader(shaderId)
//                    return 0
//                }
//            return shaderId;
//            GLES30.glGetShaderiv(fracre, GLES30.GL_COMPILE_STATUS, success, 0)
//            if (success[0] == 0) {
//                val log = GLES30.glGetShaderInfoLog(fracre)
//                Log.e(TAG, "compile vertex source failed.$log")
//                GLES30.glDeleteShader(fracre)
//                return -1
//            }

            //创建一个着色器
            val shaderId = GLES30.glCreateShader(type)
            if (shaderId != 0) {
                //加载到着色器
                GLES30.glShaderSource(shaderId, shaderCode)
                //编译着色器
                GLES30.glCompileShader(shaderId)
                //检测状态
                val compileStatus = IntArray(1)
                GLES30.glGetShaderiv(shaderId, GLES30.GL_COMPILE_STATUS, compileStatus, 0)
                if (compileStatus[0] == 0) {
                    val logInfo = GLES30.glGetShaderInfoLog(shaderId)
                    System.err.println(logInfo)
                    Log.e(TAG,type.toString()+"---");
                    Log.e(TAG,logInfo);
                    //创建失败
                    GLES30.glDeleteShader(shaderId)
                    return 0
                }
                return shaderId
            } else {
                //创建失败
                return 0
            }
        }

        fun readRawTextFile(context: Context, rawId: Int): String {
            val `is` = context.resources.openRawResource(rawId)
            val br = BufferedReader(InputStreamReader(`is`))
            var line: String?
            val sb = StringBuilder()
            try {
                while ((br.readLine().also { line = it }) != null) {
                    sb.append(line)
                    sb.append("\n")
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
            try {
                br.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
            return sb.toString()
        }
    }
}